<template>
	<view class="lime-signature" v-if="show" :style="[canvasStyle, styles]" ref="limeSignature">
		<!-- #ifndef APP-VUE || APP-NVUE -->
		<canvas 
		v-if="useCanvas2d"
		class="lime-signature__canvas"
		:id="canvasId" 
		type="2d"
		:disableScroll="disableScroll"
		@touchstart="touchStart"
		@touchmove="touchMove"
		@touchend="touchEnd"
		></canvas>
		<canvas 
		v-else
		:disableScroll="disableScroll"
		class="lime-signature__canvas"
		:canvas-id="canvasId" 
		:id="canvasId"
		:width="canvasWidth"
		:height="canvasHeight"
		@touchstart="touchStart"
		@touchmove="touchMove"
		@touchend="touchEnd"
		@mousedown="touchStart"
		@mousemove="touchMove"
		@mouseup="touchEnd"
		></canvas>
		<canvas 
			class="offscreen" 
			canvas-id="offscreen" 
			id="offscreen" 
			:style="'width:' + offscreenSize[0] + 'px;height:' + offscreenSize[1] + 'px'" 
			:width="offscreenSize[0]" 
			:height="offscreenSize[1]">
		</canvas>
		<!-- #endif -->
		<!-- #ifdef APP-VUE -->
		<view 
		:id="canvasId"
		:disableScroll="disableScroll"
		:rparam="param"
		:change:rparam="sign.update"
		
		:rclear="rclear"
		:change:rclear="sign.clear"
		
		:rundo="rundo"
		:change:rundo="sign.undo"
		
		:rsave="rsave"
		:change:rsave="sign.save"
		
		:rempty="rempty"
		:change:rempty="sign.isEmpty"
		
		></view>	
		<!-- #endif -->
		<!-- #ifdef APP-NVUE -->
		<web-view 
		src="/uni_modules/lime-signature/static/index.html"
		class="lime-signature__canvas"
		ref="webview"
		@pagefinish="onPageFinish"
		@error="onError"
		@onPostMessage="onMessage"
		></web-view>
		<!-- #endif -->
	</view>
</template>
<!-- #ifdef APP-VUE -->
<script module="sign" lang="renderjs">
export {default}  from './render'
</script>		
<!-- #endif -->

<script>
	// #ifndef APP-NVUE
	import {canIUseCanvas2d, wrapEvent, requestAnimationFrame, sleep} from './utils'
	import {Signature} from './signature'
	// import {Signature} from '@signature';
	import {uniContext, createImage, toDataURL} from './context'
	// #endif
	import props from './props';
	import {base64ToPath, getRect} from './utils'
	export default {
		props,
		data() {
			return {
				canvasWidth: null,
				canvasHeight: null,
				useCanvas2d: true,
				show: true,
				offscreenStyles: '',
				// #ifdef APP-PLUS
				rclear: 0,
				rundo: 0,
				rsave: 0,
				rempty: 0,
				risEmpty: true,
				toDataURL: null,
				tempFilePath: [],
				// #endif
			}
		},
		computed: {
			canvasId() {
				return `lime-signature${this._uid||this._.uid}`
			},
			offscreenId() {
				return this.canvasId + 'offscreen'
			},
			offscreenSize() {
				const {canvasWidth, canvasHeight} = this
				return this.landscape ? [canvasHeight, canvasWidth] : [canvasWidth, canvasHeight]
			},
			canvasStyle() {
				const {canvasWidth, canvasHeight, backgroundColor} = this
				return {
					width: canvasWidth && (canvasWidth + 'px'),
					height: canvasHeight && (canvasHeight + 'px'),
					background: backgroundColor
				}
			},
			param() {
				const {penColor, penSize, backgroundColor, landscape, openSmooth, minLineWidth, maxLineWidth, minSpeed, maxWidthDiffRate, maxHistoryLength, disableScroll} = this
				return JSON.parse(JSON.stringify({penColor, penSize, backgroundColor, landscape, openSmooth, minLineWidth, maxLineWidth, minSpeed, maxWidthDiffRate, maxHistoryLength, disableScroll}))
			}
		},
		// #ifdef APP-NVUE
		watch: {
			param(v) {
				this.$refs.webview.evalJS(`update(${JSON.stringify(v)})`)
			}
		},
		// #endif
		// #ifndef APP-PLUS
		created() {
			this.useCanvas2d = this.type == '2d' && canIUseCanvas2d()
		},
		// #endif
		// #ifndef APP-PLUS
		async mounted() {
			if(this.beforeDelay) {
				await sleep(this.beforeDelay)
			}
			const config = await this.getContext()
			this.signature = new Signature(config)
			this.canvasEl =  this.signature.canvas.get('el')
			this.canvasWidth = this.signature.canvas.get('width')
			this.canvasHeight = this.signature.canvas.get('height')
			
			this.stopWatch = this.$watch('param' , (v) => {
				this.signature.pen.setOption(v)
			}, {immediate: true})
		},
		// #endif
		// #ifndef APP-PLUS
		// #ifdef VUE3
		beforeUnmount() {
			this.stopWatch && this.stopWatch()
			this.signature.destroy()
			this.signature = null
			this.show = false;
		},
		// #endif
		// #ifdef VUE2
		beforeDestroy() {
			this.stopWatch && this.stopWatch()
			this.signature.destroy()
			this.show = false;
			this.signature = null
		},
		// #endif
		// #endif
		methods: {
			// #ifdef MP-QQ
			// toJSON() { return this },
			// #endif
			// #ifdef APP-PLUS
			onPageFinish() {
				this.$refs.webview.evalJS(`update(${JSON.stringify(this.param)})`)
			},
			onMessage(e = {}) {
				const {detail: {data: [res]}} = e
				if(res.event?.save) {
					 this.toDataURL = res.event.save
				}
				if(res.event?.changeSize) {
					const {width, height} = res.event.changeSize
				}
				if(res.event.hasOwnProperty('isEmpty')) {
					this.risEmpty = res.event.isEmpty
				}
				if (res.event?.file) {
					this.tempFilePath.push(res.event.file)
					if (this.tempFilePath.length > 7) {
						this.tempFilePath.shift()
					}
					return
				}
				if (res.event?.success) {
					if (res.event.success) {
						this.tempFilePath.push(res.event.success)
						if (this.tempFilePath.length > 8) {
							this.tempFilePath.shift()
						}
						this.toDataURL = this.tempFilePath.join('')
						this.tempFilePath = []
					} else {
						this.$emit('fail', 'canvas no data')
					}
					return
				}
			},
			// #endif
			undo() {
				// #ifdef APP-VUE || APP-NVUE
				this.rundo += 1
				// #endif
				// #ifdef APP-NVUE
				this.$refs.webview.evalJS(`undo()`)
				// #endif
				// #ifndef APP-VUE
				if(this.signature)
					this.signature.undo()
				// #endif
			},
			clear() {
				// #ifdef APP-VUE || APP-NVUE
				this.rclear += 1
				// #endif
				// #ifdef APP-NVUE
				this.$refs.webview.evalJS(`clear()`)
				// #endif
				// #ifndef APP-VUE
				if(this.signature)
					this.signature.clear()
				// #endif
			},
			isEmpty() {
				// #ifdef APP-NVUE
				this.$refs.webview.evalJS(`isEmpty()`)
				// #endif
				// #ifdef APP-VUE || APP-NVUE
				this.rempty += 1
				// #endif
				// #ifndef APP-VUE || APP-NVUE
				return this.signature.isEmpty()
				// #endif
			},
			canvasToTempFilePath(param) {
				const isEmpty = this.isEmpty()
				// #ifdef APP-NVUE
				this.$refs.webview.evalJS(`save()`)
				// #endif
				// #ifdef APP-VUE || APP-NVUE
				const stopURLWatch = this.$watch('toDataURL', (v, n) => {
					if(v && v !== n) {
						// if(param.pathType == 'url') {
						base64ToPath(v).then(res => {
							param.success({tempFilePath: res,isEmpty: this.risEmpty })
						})
						// } else {
						// 	param.success({tempFilePath: v,isEmpty: this.risEmpty })
						// }
						this.toDataURL = ''
					}
					stopURLWatch && stopURLWatch()
				})
				this.rsave += 1
				// #endif
				// #ifndef APP-VUE || APP-NVUE
				const success = (success) => param.success && param.success(success)
				const fail = (fail) => param.fail && param.fail(err)
				const {canvas} = this.signature.canvas.get('el')
				const {backgroundColor, landscape} =  this
				const width = this.signature.canvas.get('width')
				const height = this.signature.canvas.get('height')
				
				const canvasToTempFilePath = (image) => {
					const context = uni.createCanvasContext('offscreen', this)
					context.save()
					context.setTransform(1,0,0,1,0,0)
					if(landscape) {
						context.translate(0, width)
						context.rotate(-Math.PI / 2)
					}
					if(backgroundColor) {
						context.fillStyle = backgroundColor
						context.fillRect(0,0, width, height)
					}
					context.drawImage(image, 0, 0, width, height);
					
					context.draw(false, () => {
						toDataURL('offscreen', this, param).then((res) => {
							const size = Math.max(width, height)
							context.restore()
							context.clearRect(0,0, size, size)
							success({tempFilePath: res, isEmpty})
						})
					})
				}
				
				if(this.useCanvas2d) {
					try{
						// #ifndef MP-ALIPAY
						base64ToPath(canvas.toDataURL()).then(canvasToTempFilePath)
						// #endif
						// #ifdef MP-ALIPAY
						canvas.toTempFilePath({
							canvasid: this.canvasid,
							success(res){
								canvasToTempFilePath(res.tempFilePath)
							},
							fail
						})
						// #endif
					} catch(err){fail(err)}
				} else {
					toDataURL(this.canvasId, this).then(canvasToTempFilePath).catch(fail)
				}
				// #endif
			},
			// #ifndef APP-PLUS
			getContext() {
				return getRect(`#${this.canvasId}`, {context: this, type: this.useCanvas2d ? 'fields': 'boundingClientRect'}).then(res => {
					if(res) {
						let {width, height, node: canvas, left, top, right} = res
						let {pixelRatio} = uni.getSystemInfoSync()
						let context;
						if(canvas) {
							context = canvas.getContext('2d')
							canvas.width = width * pixelRatio;
							canvas.height = height * pixelRatio;
						} else {
							pixelRatio = 1
							context = uniContext(uni.createCanvasContext(this.canvasId, this))
							canvas = {
								createImage, 
								toDataURL: () => toDataURL(this.canvasId, this), 
								requestAnimationFrame
							}
						}
						// 支付宝小程序 使用stroke有个默认背景色
						context.clearRect(0,0,width,height)
						return { left, top, right, width, height, context, canvas, pixelRatio};
					}
				})
			},
			touchStart(e) {
				if(!this.canvasEl) return
				this.isStart = true
				this.canvasEl.dispatchEvent('touchstart', wrapEvent(e))
			},
			touchMove(e) {
				if(!this.canvasEl || !this.isStart && this.canvasEl) return
				this.canvasEl.dispatchEvent('touchmove', wrapEvent(e))
			},
			touchEnd(e) {
				if(!this.canvasEl) return
				this.isStart = false
				this.canvasEl.dispatchEvent('touchend', wrapEvent(e))
			},
			// #endif
		}
	}
</script>
<style lang="stylus">
	.lime-signature,.lime-signature__canvas
		// #ifndef APP-NVUE
		width: 100%;
		height: 100%
		// #endif
		// #ifdef APP-NVUE
		flex: 1;
		// #endif
	.offscreen {
		position: fixed;
		top: 0
		left: 1500rpx;
	}
</style>